/**
 * File:   Laser.cpp
 * Author: cesar
 *
 *  Este archivo contiene la implementacion de la clase Laser.hpp y sus metodos 
 *
 */

#include "Laser.hpp"

/**
 * Constructor de la clase Laser
 * 
 * @param light : Enumeracion que indica la luz de openGL a utilizar en el laser
 * @param pos_x : Posicion inicial en el eje X 
 * @param pos_y : Posicion inicial en el eje Y
 * @param pos_z : Posicion inicial en el eje Z
 */
Laser::Laser(GLenum light, GLfloat pos_x, GLfloat pos_y, GLfloat pos_z) : ObjetoGrafico(pos_x, pos_y, pos_z) {
    vector[0] = 0.0;
    vector[1] = 0.0;
    vector[2] = -2.0;
    activo = false;
    tope = 300.0;
    luz = light;

    //reflexion ambiental del material
    material_ambient[0] = 0.5;
    material_ambient[1] = 0.0;
    material_ambient[2] = 0.0;

    //reflexion difusa del material
    material_difuso[0] = 1.0;
    material_difuso[1] = 0.0;
    material_difuso[2] = 0.0;


    //reflexion especular del material
    material_especular[0] = 0.727811;
    material_especular[1] = 0.626959;
    material_especular[2] = 0.626959;

    //emision de luz roja
    material_emision[0] = 1.0;
    material_emision[1] = 0.0;
    material_emision[2] = 0.0;

    //brillo
    material_brillo[0] = 128.0;


    //cargamos el sonido del laser 
    cargarSonido("laser.wav", false);


}

/**
 * Metodo idle del laser, permite calcular su movimiento.
 * @param s : El frameskip actual.
 */
void Laser::idle(int s) {
    if (activo) {
        //se mueve el laser mediante un vector
        this->vectorialMove(s);
    }
}


/**
 * Metodo que permite dibujar el laser en la escena si este se encuentra
 * activo( fue disparado por la nave)
 */
void Laser::dibujar() {

    if (activo) {
        
        GLfloat position[] = {x, y, z, 0.0};
        
        glPushMatrix();
        
        glTranslatef(x, y, z);
        glRotatef(180.0, 1.0, 0.0, 0.0);

        glRotatef(-acos((-2 * vector[2]) / 4), 0.0, 1.0, 0.0);

        //se coloca una luz puntual junto al laser
        glLightfv(luz, GL_POSITION, position);

        //se configura los materiales para que el laser sea de color rojo
        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, material_ambient);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material_difuso);
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material_especular);
        glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, material_emision);
        glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, material_brillo);
        glutSolidCone(0.15, 4.0, 5, 5);



        glPopMatrix();



    }




}


/**
 * Este metodo permite colocar una posicion inicial al laser antes de 
 * ser disparado. 
 * 
 * @param px : Posicion en el eje X.
 * @param py : Posicion en el eje Y.
 * @param pz : Posicion en el eje Z.
 */
void Laser::setInitialPosition(GLfloat px, GLfloat py, GLfloat pz) {
    x = initial[0] = px;
    y = initial[1] = py;
    z = initial[2] = pz;




}


/**
 * Este metodo permite mover el laser mediante un vector de velocidad.
 * 
 * @param s: El frameskip actual.
 */
void Laser::vectorialMove(int s) {
    //si el laser no llega a la distancia tope seguir moviendo
    if (pow(tope, 2)>(pow((x - initial[0]), 2) + pow((y - initial[1]), 2) + pow((z - initial[2]), 2))) {
        x += vector[0] * s;
        y += vector[1] * s;
        z += vector[2] * s;
    } else {
        activo = false;
        glDisable(luz);
        x = y = z = 0;
    }

}



/**
 * Esta funcion permite obtener la enumeracion que corresponde a la luz 
 * asignada al laser.
 * 
 * @return La enumeracion de OpenGL que corresponde a la luz utilizada. 
 */
GLenum Laser::getLuz() {

    return luz;
}

/**
 * Este metodo permite restaurar los valores por defecto del laser
*/
void Laser::restaurarLuz() {


    GLfloat diffuse_laser[] = {1.0, 0.1, 0.1, 1.0};
    GLfloat ambiental_laser[] = {0.2, 0.0, 0.0, 1.0};
    GLfloat especular[] = {1.0, 1.0, 1.0, 1.0};

    glLightfv(luz, GL_DIFFUSE, diffuse_laser);
    glLightfv(luz, GL_AMBIENT, ambiental_laser);
    glLightfv(luz, GL_SPECULAR, especular);
    glLightf(luz, GL_CONSTANT_ATTENUATION, 0.7);
    glLightf(luz, GL_LINEAR_ATTENUATION, 0.0);
    glLightf(luz, GL_QUADRATIC_ATTENUATION, 0.05);
    glDisable(luz);


}


/**
 * Este metodo habilita el laser para ser dibujado despues de ser disparado
 */
void Laser::activar() {
    // reinicia el vector velocidad
    vector[0] = 0.0;
    vector[1] = 0.0;
    vector[2] = -2.0;
    activo = true;
    restaurarLuz();
    glEnable(luz);
    //reproducir sonido de laser.
    alSourcePlay(source[0]);
}

/**
 * Este metodo deshabilita el laser y lo hace invisible en la escena.
 * @param apagar : Indica si se quiere desactivar tambien la luz del laser(true).
 */
void Laser::desactivar(bool apagar) {
    activo = false;

    if (apagar) {
        glDisable(luz);
    }
}


/**
 * Esta funcion indica si el laser esta activado(true) o no(false).
 * @return activado(true) o no(false).
 */
bool Laser::activado() {
    return activo;
}


/**
 * Este metodo permite indicar al laser la posicion de su objetivo.
 * 
 * @param x2 : La posicion del Objetivo en el eje X.
 * @param y2 : La posicion del Objetivo en el eje Y.
 * @param z2 : La posicion del Objetivo en el eje Z.
 */
void Laser::setTarget(GLfloat x2, GLfloat y2, GLfloat z2) {
    
      //se define la velocidad del laser con modulo 2
    double d = sqrt(pow((x - x2), 2) + pow((y - y2), 2) + pow((z - z2), 2));
    double m = d / 2;
    vector[0] = (x2 - x) / m;
    vector[1] = (y2 - y) / m;
    vector[2] = (z2 - z) / m;

}